package com.example.demo_yunpan.service.impl;

import com.example.demo_yunpan.entity.file;
import com.example.demo_yunpan.mapper.FileMapper;
import com.example.demo_yunpan.service.HdfsFileService;

import org.apache.commons.io.FilenameUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import static com.example.demo_yunpan.service.HadoopConnectivityTest.listFilesInDirectory;

@Service
public class HdfsFileServiceImpl implements HdfsFileService {

    @Autowired
    FileMapper fileMapper;

    private FileSystem fs;
    /**
     * @param
     */
    /*private static final String HDFS_URI = "hdfs://172.17.243.232:9000";
    public HdfsFileServiceImpl() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf = new Configuration();
        fs = FileSystem.get(new URI(HDFS_URI),conf);
    }*/



    public HdfsFileServiceImpl() throws URISyntaxException {
        URI uri = new URI("hdfs://hadoop1:9000");
        Configuration conf = new Configuration();
        conf.set("dfs.client.use.datanode.hostname", "true");
        try {
            fs = FileSystem.get(uri, conf);
            Path rootPath = new Path("/");
            if (fs.exists(rootPath)) {
                System.out.println("Successfully connected to HDFS at " );
                System.out.println("HDFS Root Path Exists: " + rootPath);
                // 列出HDFS某个目录下的所有文件
                listFilesInDirectory(fs, new Path("/tmp")); // 替换为您要列出文件的HDFS目录
            } else {
                System.out.println("Failed to connect to HDFS or the root path does not exist.");
            }
            // 现在可以使用fs对象与HDFS进行交互
        } catch (IOException e) {
            // 处理IOException
            e.printStackTrace();
        }
    }


    @Override
    public List<String> getFileList(String path) throws IOException {
        List<String> fileList = new ArrayList<>();
        Path hdfsPath = new Path("/"+path);
        System.out.println(hdfsPath);
        System.out.println(fs.exists(hdfsPath));
        if (fs.exists(hdfsPath)) {
            FileStatus[] status = fs.listStatus(hdfsPath);
            for (FileStatus file : status) {
                fileList.add(file.getPath().getName());
            }
        }
        return fileList;
    }

    @Override
    public ResponseEntity<String> uploadFile(MultipartFile file, String folderName, int userId, String hdfsPath) {
        // 文件名冲突检查和重命名逻辑
        String originalFileName = file.getOriginalFilename();
        String hdfsFileName = checkAndRenameFileName(originalFileName,folderName);
        //String hdfsPath = getHdfsPath(folderName, hdfsFileName); // 假设您有一个方法来构建HDFS路径

        try {
            // 文件上传到HDFS
            byte[] fileBytes = file.getBytes();
            Path hdfsPathObj = new Path(hdfsPath);
            FSDataOutputStream out = fs.create(hdfsPathObj);
            out.write(fileBytes);
            out.close();

            // 构建file实体并保存到数据库
            file dbFile = new file();
            dbFile.setFileName(originalFileName); // 保存原始文件名
            dbFile.setFolderId(dbFile.getFolderId());
            dbFile.setFiletype(file.getContentType()); // 或者从其他逻辑获取filetype
            dbFile.setUserId(userId);
            dbFile.setCreateTime(new Timestamp(System.currentTimeMillis()));
            dbFile.setFileSize((double) file.getSize());
            dbFile.setHdfsPath(hdfsPath);

            // 假设fileID是自增的，数据库会自动处理这部分
            // 调用Mapper层的insertFile方法保存文件信息
            int result = fileMapper.insertFile(dbFile);
            if (result > 0) {
                return ResponseEntity.ok("文件上传成功，HDFS路径：" + hdfsPath);
            } else {
                // 可能需要处理文件从HDFS的删除，或者只是记录错误
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("保存文件信息到数据库失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("文件上传时发生异常");
        }
    }

    /**
     * 文件下载
     * @param fileId
     * @param localFilePath
     * @return
     * @throws IOException
     */
    @Override
    public void downloadFile(int fileId, String localFilePath) throws IOException {
        Path hdfsPath = new Path(fileMapper.getHdfsPathByFileId(fileId) ); // 假设hdfsBasePath是HDFS的根路径
        FSDataInputStream inputStream = fs.open(hdfsPath);

        try (FileOutputStream outputStream = new FileOutputStream(localFilePath)) {
            byte[] buffer = new byte[4096]; // 可以根据需要调整缓冲区大小
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } finally {
            IOUtils.closeStream(inputStream);
        }
    }

    public String getFileName(int FileId) throws IOException{
        return fileMapper.getFileNameById(FileId);
    }

    @Override
    public boolean reNameFile(String oldName, String newName, String currentPath) throws IOException {
        Path oldPath = new Path(currentPath + "/" + oldName);
        Path newPath = new Path(currentPath + "/" + newName);
        return fs.rename(oldPath, newPath);
    }

    @Override
    public boolean delFile(String fileName, String currentPath) throws IOException {
        // 构造HDFS中的文件路径
        String hdfsPath = currentPath + "/" + fileName;

        // 查找文件的ID
        String fileId = fileMapper.getFileIdByFileNameAndPath(fileName, hdfsPath);
        if (fileId == null) {
            // 文件不存在，返回false
            return false;
        }

        // 将文件标记为在回收站
        boolean updated = fileMapper.upFileMarkTrue(fileId);
        if (updated) {
            // 更新成功，返回true
            return true;
        } else {
            // 更新失败，返回false
            return false;
        }
    }

    @Override
    public boolean createFile(String newName, String currentPath) throws IOException {
        Path path = new Path(currentPath + "/" + newName);
        if (!fs.exists(path)) {
            FSDataOutputStream out = fs.create(path);
            out.close();
            return true;
        }
        return false;
    }

    @Override
    public boolean moveTo(String oldName, String newPath, String currentPath) throws IOException {
        Path oldPath = new Path(currentPath + "/" + oldName);
        Path newFullPath = new Path(newPath + "/" + oldName);
        return fs.rename(oldPath, newFullPath);
    }

    @Override
    public List<file> selectfile(String currentPath, String type, Map<String, Set<String>> map) throws IOException {
        List<file> fileList = new ArrayList<>();
        Path hdfsPath = new Path(currentPath);

        if (fs.exists(hdfsPath)) {
            FileStatus[] status = fs.listStatus(hdfsPath);
            Pattern pattern = Pattern.compile(type); // 将type转换为正则表达式模式

            for (FileStatus fileStatus : status) {
                String fileName = fileStatus.getPath().getName();
                if (pattern.matcher(fileName).matches()) { // 如果文件名匹配type模式
                    // 这里我们假设其他file实体类的属性可以从其他地方获取或设置为默认值
                    file fileObj = new file();
                    fileObj.setFileName(fileName);
                    // ... 设置其他属性，如fileObj.setFolderId(defaultFolderId);

                    // 添加到结果列表
                    fileList.add(fileObj);
                }
            }
        }
        return fileList;
    }

    @Override
    public boolean fileExist(String path) throws IOException {
        Path hdfsPath = new Path(path);
        return fs.exists(hdfsPath);
    }

    @Override
    public List<file> findFileByUserId(String userId, String path) {
        return fileMapper.findFileByUserId(userId, path);
    }

    /**
     * 查询同一个用户Id的所有文件夹
     * @param userId,fileNameFuzzy,category
     * return List<folder>
     * */
    @Override
    public List<file> findAllByuserId(String userId, String fileNameFuzzy, String category){
        return fileMapper.selectAllByuserId(userId,fileNameFuzzy,category);
    }
    public void close() throws IOException {
        if (fs != null) {
            fs.close();
        }
    }
    @Override
    public String checkAndRenameFileName(String fileName, String folderName) {
        // 检查文件名冲突并重新命名
        String baseName = FilenameUtils.getBaseName(fileName);
        String extension = FilenameUtils.getExtension(fileName);
        String newFileName = fileName;
        int count = 1;
        while (fileMapper.selectFileByName(newFileName, folderName) != null) {
            newFileName = baseName + "(" + count + ")." + extension;
            count++;
        }
        return newFileName;
    }

}
